from dataclasses import dataclass
from enum import Enum

from common.credentials import Credentials, LMHash, NTHash, Password, get_plaintext
from infection_monkey.i_puppet import TargetHost

from .powershell_consts import POWERSHELL_SSL_PORT


class AuthenticationType(Enum):
    BASIC = "basic"
    NEGOTIATE = "negotiate"
    NTLM = "ntlm"


class EncryptionSetting(Enum):
    AUTO = "auto"
    NEVER = "never"


@dataclass
class AuthenticationOptions:
    authentication_type: AuthenticationType
    encryption_setting: EncryptionSetting
    ssl_enabled: bool


def get_auth_options(credentials: Credentials, host: TargetHost) -> AuthenticationOptions:
    ssl_enabled = _get_ssl_enabled_option(credentials, host)
    authentication_type = _get_authentication_type(credentials)
    encryption_setting = _get_encryption_setting(credentials)

    return AuthenticationOptions(authentication_type, encryption_setting, ssl_enabled)


def _get_ssl_enabled_option(credentials: Credentials, host: TargetHost) -> bool:
    # Passwordless login only works with SSL false,
    # AuthenticationType.BASIC and EncryptionSetting.NEVER
    if isinstance(credentials.secret, Password):
        if get_plaintext(credentials.secret.password) == "":
            return False

    # Check if default PSRemoting ports are open. Prefer with SSL, if both are.
    return POWERSHELL_SSL_PORT in host.ports_status.tcp_ports.open


def _get_authentication_type(credentials: Credentials):
    if isinstance(credentials.secret, Password):
        if get_plaintext(credentials.secret.password) == "":
            return AuthenticationType.BASIC

    if isinstance(credentials.secret, LMHash) or isinstance(credentials.secret, NTHash):
        return AuthenticationType.NTLM

    return AuthenticationType.NEGOTIATE


def _get_encryption_setting(credentials: Credentials):
    secret = None
    if isinstance(credentials.secret, Password):
        secret = get_plaintext(credentials.secret.password)
    return EncryptionSetting.NEVER if secret == "" else EncryptionSetting.AUTO
